package com.gjp.processdemo.config;

import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.BpmnAutoLayout;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.Process;
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
import org.flowable.editor.language.json.converter.util.CollectionUtils;
import org.flowable.engine.IdentityService;
import org.flowable.engine.RepositoryService;
import org.flowable.idm.api.Group;
import org.flowable.idm.api.User;
import org.flowable.ui.common.service.exception.BadRequestException;
import org.flowable.ui.common.util.XmlUtil;
import org.flowable.ui.modeler.domain.Model;
import org.flowable.ui.modeler.model.ModelRepresentation;
import org.flowable.ui.modeler.serviceapi.ModelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.util.ResourceUtils;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.*;
import java.util.zip.ZipInputStream;

/**
 * spring 容器初始化完毕后，执行自己的初始化逻辑
 *
 * @author 51101
 */
@Component
@Slf4j
public class Initialized implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private IdentityService identityService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ModelService modelService;
    private Boolean isInit = false;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        synchronized (Initialized.class) {
            if (!isInit) {
                isInit = true;
                log.info("开始初始化......");
                initUser();
                initGroup();
                initUserToGroup();
                initDeploy();
                log.info("初始化完毕。");
            }
        }
    }

    /**
     * 初始化用户
     */
    private void initUser() {
        log.info("初始化用户");
        //初始化流程所需要的身份信息
        User user1 = identityService.newUser("10086");
        user1.setLastName("郭金鹏");
        user1.setPassword("123456");
        user1.setEmail("511015986@qq.com");

        User user2 = identityService.newUser("10087");
        user2.setLastName("彭国杰");
        user2.setPassword("123456");
        user2.setEmail("12233431@qq.com");

        User user3 = identityService.newUser("10088");
        user3.setLastName("徐秋伟");
        user3.setPassword("123456");
        user3.setEmail("84431293@qq.com");

        identityService.saveUser(user1);
        identityService.saveUser(user2);
        identityService.saveUser(user3);
    }

    /**
     * 初始化用户组
     */
    private void initGroup() {
        log.info("初始化用户组");
        Group groupEntity1 = identityService.newGroup("10086");
        groupEntity1.setName("web开发");
        groupEntity1.setType("开发");
        identityService.saveGroup(groupEntity1);

        Group groupEntity2 = identityService.newGroup("10087");
        groupEntity2.setName("人事部");
        groupEntity2.setType("行政");
        identityService.saveGroup(groupEntity2);

        Group groupEntity3 = identityService.newGroup("10088");
        groupEntity3.setName("经理");
        groupEntity3.setType("高层");
        identityService.saveGroup(groupEntity3);
    }

    /**
     * 初始化用户与组之间的关系
     */
    private void initUserToGroup() {
        log.info("初始化用户与用户组之间的关系");
        identityService.createMembership("10086", "10086");
        identityService.createMembership("10087", "10087");
        identityService.createMembership("10088", "10088");
    }

    /**
     * 部署已zip结尾的流程定义文件
     */
    private void initDeploy() {
        log.info("部署流程定义文件");
        try {
            File processes = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX + "processes");
            for (File file : processes.listFiles()) {
                String fileName = file.getName();
                //如果文件已zip结尾，则直接部署
                if (fileName.endsWith(".zip")) {
                    repositoryService
                            .createDeployment()
                            .addZipInputStream(
                                    new ZipInputStream(
                                            new FileInputStream(file)))
                            .deploy();
                } else if (fileName.endsWith(".bpmn20.xml") || fileName.endsWith(".bpmn")) {
                    BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
                    BpmnJsonConverter bpmnJsonConverter = new BpmnJsonConverter();

                    XMLInputFactory xif = XmlUtil.createSafeXmlInputFactory();
                    InputStreamReader xmlIn = new InputStreamReader(new FileInputStream(file), "UTF-8");
                    XMLStreamReader xtr = xif.createXMLStreamReader(xmlIn);
                    BpmnModel bpmnModel = bpmnXMLConverter.convertToBpmnModel(xtr);
                    if (CollectionUtils.isEmpty(bpmnModel.getProcesses())) {
                        throw new BadRequestException("在定义中找不到流程 " + fileName);
                    } else {
                        if (bpmnModel.getLocationMap().size() == 0) {
                            BpmnAutoLayout bpmnLayout = new BpmnAutoLayout(bpmnModel);
                            bpmnLayout.execute();
                        }

                        ObjectNode modelNode = bpmnJsonConverter.convertToJson(bpmnModel);
                        Process process = bpmnModel.getMainProcess();
                        String name = process.getId();
                        if (StringUtils.isNotEmpty(process.getName())) {
                            name = process.getName();
                        }

                        String description = process.getDocumentation();
                        ModelRepresentation model = new ModelRepresentation();
                        model.setKey(process.getId());
                        model.setName(name);
                        model.setDescription(description);
                        model.setModelType(0);
                        //以管理员身份创建
                        User admin = identityService
                                .createUserQuery()
                                .userLastName("郭金鹏")
                                .singleResult();
                        Model newModel = this.modelService.createModel(
                                model,
                                modelNode.toString(),
                                admin
                        );
                        // 部署
                        deployment(newModel.getId());
                    }
                }
            }
        } catch (FileNotFoundException | UnsupportedEncodingException | XMLStreamException e) {
            e.printStackTrace();
        }
    }

    /**
     * 部署 model
     *
     * @param modelId
     */
    public void deployment(String modelId) {
        Model model = modelService.getModel(modelId);
        BpmnModel bpmnModel = modelService.getBpmnModel(model);
        repositoryService
                .createDeployment()
                .name(model.getName())
                .addBpmnModel(model.getKey() + ".bpmn", bpmnModel)
                .deploy();

    }

}
